Introduction

In this project, we are using a dataset of songs on the music streaming app Spotify.

The dataset contains songs on Spotify across multiple genres, and we will be performing several analyses to this dataset, such as basic descriptive and bivariate statistics, Principal Component Analysis, decision trees, regression, and clustering.

Here is the link to the original dataset

First, we import the data to R and make sure R is reading the data properly.

# importing relevant libraries to perform cleaning on the data
library(tidyverse)
library(janitor)
setwd("~/Documents/class/stats-final-project/")
# importing the data and cleaning the names into a snake_case format.
raw_data <- read.csv("dataset.csv") %>% clean_names() 

The dataset has 114,000 rows and 21 columns/variables.

It has the following scores (numerical variables): * popularity: The popularity of a track is a value between 0 and 100, with 100 being the most popular. - duration_ms: The track length in milliseconds - danceability: Danceability describes how suitable a track is for dancing based on a combination of musical elements including tempo, rhythm stability, beat strength, and overall regularity. A value of 0.0 is least danceable and 1.0 is most danceable - energy: Energy is a measure from 0.0 to 1.0 and represents a perceptual measure of intensity and activity. Typically, energetic tracks feel fast, loud, and noisy. For example, death metal has high energy, while a Bach prelude scores low on the scale - loudness: The overall loudness of a track in decibels (dB) - speechiness: Speechiness detects the presence of spoken words in a track. The more exclusively speech-like the recording (e.g. talk show, audio book, poetry), the closer to 1.0 the attribute value. - acousticness: A confidence measure from 0.0 to 1.0 of whether the track is acoustic. 1.0 represents high confidence the track is acoustic - instrumentalness: Predicts whether a track contains no vocals. “Ooh” and “aah” sounds are treated as instrumental in this context. Rap or spoken word tracks are clearly “vocal”. The closer the instrumentalness value is to 1.0, the greater likelihood the track contains no vocal content - liveness: Detects the presence of an audience in the recording. Higher liveness values represent an increased probability that the track was performed live. A value above 0.8 provides strong likelihood that the track is live - valence: A measure from 0.0 to 1.0 describing the musical positiveness conveyed by a track. Tracks with high valence sound more positive (e.g. happy, cheerful, euphoric), while tracks with low valence sound more negative (e.g. sad, depressed, angry) - tempo: The overall estimated tempo of a track in beats per minute (BPM). In musical terminology, tempo is the speed or pace of a given piece and derives directly from the average beat duration

The dataset also has the following categorical variables: - explicit: Whether or not the track has explicit lyrics (true = yes it does; false = no it does not OR unknown) - mode: Mode indicates the modality (major or minor) of a track, the type of scale from which its melodic content is derived. Major is represented by 1 and minor is 0 - key: The key the track is in. Integers map to pitches using standard Pitch Class notation. E.g. 0 = C, 1 = C♯/D♭, 2 = D, and so on. If no key was detected, the value is -1 - track_genre: The genre in which the track belongs

It also has the following columns that describe the songs: - track_id: The Spotify ID for the track - artists: The artists’ names who performed the track. If there is more than one artist, they are separated by a ; - album_name: The album name in which the track appears - track_name: Name of the track

Now we are performing several checks on the data

#dim(raw_data)
#names(raw_data)
#sapply(raw_data, class)

We’ll perform the following transforms to the data in order to prepare it for our analysis:

Since some of the categorical variables - mode, key, and time_signature - are currently codified as numerical, we will do the following: 1. key: We will be converting them from numbers 0 to 11 to the letter value of the key (C = 0, C# = 1, etc.) 2. mode: Instead of 0 for minor and 1 for major, we’ll convert them to “major” and “minor”. 3. time_signature: We’ll convert into characters instead of numeric.

We are also adding 2 more variables, which are: 1. multiple_artists: If there are multiple artists performing the track, the artists column will contain all artists separated by a semicolon (;). We’ll add a true value in this column if there are multiple artists, and false if a single artist. 2. tempo_cat: this is a categorical variable based on the tempo column. We’ll use the beats per minute to determine which tempo marking it fits in. This will be an ordinal variable, with the levels defined.

We are also performing several filters to scope our analysis: 1. Filter to songs that are done by popular artists. This is done by finding the artists that have 20 songs or more and filtering to just the songs by those artists. 2. We also scope the analysis to just songs that are less than 10 minutes. 3. We’ll also remove the duplicated songs. This is because some songs are listed in albums or single versions. This is done by removing songs that have the same variable in the track_name and artists columns. 4. We also sample the data to just 3,000 rows/songs. This is done by random sampling using the sample_n() function.

Finally, we’ll just select the columns that are relevant to us in our analysis, and remove the descriptive columns, track_id, artists, album_name, and track_name.

# creating a list of keys from C to B
key_alpha <- c('C','C#/Db','D','D#/Eb','E','F','F#/Gb','G','G#/Ab','A','A#/Bb','B')

# creating a new df for mapping keys
key_map <- data.frame(key = c(0:11),
                      key_alpha = key_alpha)

data <- raw_data %>%
  full_join(key_map, "key") %>% 
  mutate(mode = str_replace(as.character(mode), "0", "minor"),
         mode = str_replace(as.character(mode), "1", "major"),
         time_signature = as.character(time_signature),
         # converting keys to alphabet
         key = key_alpha,
         # adding a column for whether the artist is one or multiple. True for Multiple, false for single
         multiple_artists = grepl(";", artists)
         ) %>% 
  select(-1, -22) %>%
  # removing duplicates in songs, because some tracks are in multiple albums
  distinct(track_name, artists, .keep_all = TRUE)

# finding the popular artists, with more than 20 songs listed.
popular_artists <- data %>% group_by(artists) %>% 
  summarize(count = n()) %>% 
  filter(count >= 20) 

filtered <- data %>% filter(artists %in% popular_artists$artists) %>% 
  filter(duration_ms <= 600000) %>%
  #removing the track_id, title, artists, albums because it's not needed.
  select(5:21) %>%
  mutate(
  # adding an ordinal variable for tempo
  tempo_cat = cut(tempo,
              breaks=c(0, 20, 40, 60, 66, 76, 108, 120, 168, 176, 200, 1000),
              labels=c('Larghissimo','Grave','Lento/Largo','Larghetto','Adagio','Andante','Moderato','Allegro','Vivace','Presto','Prestissimo'))
)

# random sampling the data to just 3000 songs
set.seed(1)
dd <- filtered %>% sample_n(3000)

# attaching the column names
attach(dd)

# for one-time exporting for other analysis
# dd %>% write_csv("cleaneddata.csv")

Descriptive Statistics

n<-dim(dd)[1]
K<-dim(dd)[2]

descriptiva<-function(X, nom){
  if (!(is.numeric(X) || class(X)=="Date")){ 
    frecs<-table(as.factor(X), useNA="ifany")
    proportions<-frecs/n
    #ojo, decidir si calcular porcentages con o sin missing values
    pie(frecs, cex=0.6, main=paste("Pie of", nom))
    barplot(frecs, las=3, cex.names=0.7, main=paste("Barplot of", nom), col=listOfColors)
    print(paste("Number of modalities: ", length(frecs)))
    print("Frequency table")
    print(frecs)
    print("Relative frequency table (proportions)")
    print(proportions)
    print("Frequency table sorted")
    print(sort(frecs, decreasing=TRUE))
    print("Relative frequency table (proportions) sorted")
    print(sort(proportions, decreasing=TRUE))
   }else{
     if(class(X)=="Date"){
       print(summary(X))
       print(sd(X))
       #decide breaks: weeks, months, quarters...
       hist(X,breaks="weeks")
     }else{
       hist(X, main=paste("Histogram of", nom))
       boxplot(X, horizontal=TRUE, main=paste("Boxplot of",nom))
       print("Extended Summary Statistics")
       print(summary(X))
       print(paste("sd: ", sd(X, na.rm=TRUE)))
       print(paste("vc: ", sd(X, na.rm=TRUE)/mean(X, na.rm=TRUE)))
      }
   }
}

dataset<-dd
actives<-c(1:K)
colDate<-1
if (dataset=="platjaDaro")
  {dd[,colDate]<-as.Date(dd[, colDate], format="%d/%m/%y %h:%m:%s")
   actives<-c(3:44)
   }
Warning: the condition has length > 1 and only the first element will be used
listOfColors<-rainbow(39)

par(ask=TRUE)

for(k in actives){
  print(paste("variable ", k, ":", names(dd)[k] ))
  descriptiva(dd[,k], names(dd)[k])
}
[1] "variable  1 : popularity"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
   0.00   19.00   30.00   32.78   46.00   97.00 
[1] "sd:  19.071854500815"
[1] "vc:  0.581754585688306"
[1] "variable  2 : duration_ms"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
  28946  167156  215889  224103  268796  594533 
[1] "sd:  86933.4740717619"
[1] "vc:  0.387917069526423"
[1] "variable  3 : explicit"

[1] "Number of modalities:  2"
[1] "Frequency table"

False  True 
 2812   188 
[1] "Relative frequency table (proportions)"

     False       True 
0.93733333 0.06266667 
[1] "Frequency table sorted"

False  True 
 2812   188 
[1] "Relative frequency table (proportions) sorted"

     False       True 
0.93733333 0.06266667 
[1] "variable  4 : danceability"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.4270  0.5480  0.5410  0.6653  0.9750 
[1] "sd:  0.176265638860442"
[1] "vc:  0.325833140160227"
[1] "variable  5 : energy"

[1] "Extended Summary Statistics"
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
0.000242 0.423000 0.666500 0.624997 0.861250 0.999000 
[1] "sd:  0.265941258309461"
[1] "vc:  0.42550798946771"
[1] "variable  6 : key"

[1] "Number of modalities:  12"
[1] "Frequency table"

    A A#/Bb     B     C C#/Db     D D#/Eb     E     F F#/Gb     G G#/Ab 
  326   187   221   366   250   346    90   269   252   160   383   150 
[1] "Relative frequency table (proportions)"

         A      A#/Bb          B          C      C#/Db          D      D#/Eb          E          F      F#/Gb 
0.10866667 0.06233333 0.07366667 0.12200000 0.08333333 0.11533333 0.03000000 0.08966667 0.08400000 0.05333333 
         G      G#/Ab 
0.12766667 0.05000000 
[1] "Frequency table sorted"

    G     C     D     A     E     F C#/Db     B A#/Bb F#/Gb G#/Ab D#/Eb 
  383   366   346   326   269   252   250   221   187   160   150    90 
[1] "Relative frequency table (proportions) sorted"

         G          C          D          A          E          F      C#/Db          B      A#/Bb      F#/Gb 
0.12766667 0.12200000 0.11533333 0.10866667 0.08966667 0.08400000 0.08333333 0.07366667 0.06233333 0.05333333 
     G#/Ab      D#/Eb 
0.05000000 0.03000000 
[1] "variable  7 : loudness"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
-42.631 -11.155  -7.498  -8.888  -5.181   0.377 
[1] "sd:  5.32258438263559"
[1] "vc:  -0.598842498009395"
[1] "variable  8 : mode"

[1] "Number of modalities:  2"
[1] "Frequency table"

major minor 
 2022   978 
[1] "Relative frequency table (proportions)"

major minor 
0.674 0.326 
[1] "Frequency table sorted"

major minor 
 2022   978 
[1] "Relative frequency table (proportions) sorted"

major minor 
0.674 0.326 
[1] "variable  9 : speechiness"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
0.00000 0.03470 0.04690 0.07862 0.07490 0.96200 
[1] "sd:  0.103964236837045"
[1] "vc:  1.32239625374972"
[1] "variable  10 : acousticness"

[1] "Extended Summary Statistics"
    Min.  1st Qu.   Median     Mean  3rd Qu.     Max. 
0.000001 0.013300 0.217000 0.348478 0.678250 0.996000 
[1] "sd:  0.349889758582825"
[1] "vc:  1.00405207937953"
[1] "variable  11 : instrumentalness"

[1] "Extended Summary Statistics"
     Min.   1st Qu.    Median      Mean   3rd Qu.      Max. 
0.0000000 0.0000000 0.0000889 0.1887061 0.1462500 1.0000000 
[1] "sd:  0.33859412273214"
[1] "vc:  1.7942934790234"
[1] "variable  12 : liveness"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0112  0.1010  0.1410  0.2379  0.3070  0.9920 
[1] "sd:  0.216531534653923"
[1] "vc:  0.910165401744503"
[1] "variable  13 : valence"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
 0.0000  0.2500  0.4730  0.4771  0.6933  0.9850 
[1] "sd:  0.267153566864831"
[1] "vc:  0.559899974951364"
[1] "variable  14 : tempo"

[1] "Extended Summary Statistics"
   Min. 1st Qu.  Median    Mean 3rd Qu.    Max. 
    0.0   100.0   121.9   121.9   139.7   220.0 
[1] "sd:  29.448628745521"
[1] "vc:  0.241613772469231"
[1] "variable  15 : time_signature"

[1] "Number of modalities:  5"
[1] "Frequency table"

   0    1    3    4    5 
   4   30  271 2636   59 
[1] "Relative frequency table (proportions)"

          0           1           3           4           5 
0.001333333 0.010000000 0.090333333 0.878666667 0.019666667 
[1] "Frequency table sorted"

   4    3    5    1    0 
2636  271   59   30    4 
[1] "Relative frequency table (proportions) sorted"

          4           3           5           1           0 
0.878666667 0.090333333 0.019666667 0.010000000 0.001333333 
[1] "variable  16 : track_genre"

[1] "Number of modalities:  100"
[1] "Frequency table"

         acoustic          afrobeat          alt-rock       alternative           ambient             anime 
               23                41                46                 8                41                32 
      black-metal         bluegrass             blues            brazil         breakbeat           british 
               17                41                 2                19                36                71 
         cantopop     chicago-house          children             chill         classical              club 
               51                67                98                 6                22                24 
           comedy           country             dance         dancehall       death-metal    detroit-techno 
               32                 5                 2                14                21                79 
            disco            disney     drum-and-bass               edm           electro        electronic 
                4                43                 4                 3                11                19 
              emo              folk             forro            garage            german            gospel 
               30                18                50                33                24                14 
             goth         grindcore            groove            grunge            guitar             happy 
               47                49                34                44                31                30 
        hard-rock          hardcore       heavy-metal           hip-hop        honky-tonk               idm 
               45                12               103                 8               109                61 
           indian             indie         indie-pop        industrial           iranian           j-dance 
                9                 1                 2                47                44                26 
           j-idol             j-pop            j-rock              jazz             k-pop              kids 
              110                12                16                 2                37                84 
            latin            latino             malay          mandopop             metal         metalcore 
                1                 3                36                23                14                30 
   minimal-techno               mpb           new-age             opera            pagode             party 
                6                16                63                20                59                20 
            piano               pop          pop-film         power-pop progressive-house        psych-rock 
               28                 1                 3                28                 4                37 
             punk         punk-rock             r-n-b       rock-n-roll        rockabilly           romance 
                5                17                11                35                29                53 
            salsa             samba         sertanejo        show-tunes singer-songwriter               ska 
               21                24                44                18                 8                40 
            sleep           spanish             study           swedish         synth-pop             tango 
               34                11                74                 7                18                45 
           trance          trip-hop           turkish       world-music 
               10                27                 7                56 
[1] "Relative frequency table (proportions)"

         acoustic          afrobeat          alt-rock       alternative           ambient             anime 
     0.0076666667      0.0136666667      0.0153333333      0.0026666667      0.0136666667      0.0106666667 
      black-metal         bluegrass             blues            brazil         breakbeat           british 
     0.0056666667      0.0136666667      0.0006666667      0.0063333333      0.0120000000      0.0236666667 
         cantopop     chicago-house          children             chill         classical              club 
     0.0170000000      0.0223333333      0.0326666667      0.0020000000      0.0073333333      0.0080000000 
           comedy           country             dance         dancehall       death-metal    detroit-techno 
     0.0106666667      0.0016666667      0.0006666667      0.0046666667      0.0070000000      0.0263333333 
            disco            disney     drum-and-bass               edm           electro        electronic 
     0.0013333333      0.0143333333      0.0013333333      0.0010000000      0.0036666667      0.0063333333 
              emo              folk             forro            garage            german            gospel 
     0.0100000000      0.0060000000      0.0166666667      0.0110000000      0.0080000000      0.0046666667 
             goth         grindcore            groove            grunge            guitar             happy 
     0.0156666667      0.0163333333      0.0113333333      0.0146666667      0.0103333333      0.0100000000 
        hard-rock          hardcore       heavy-metal           hip-hop        honky-tonk               idm 
     0.0150000000      0.0040000000      0.0343333333      0.0026666667      0.0363333333      0.0203333333 
           indian             indie         indie-pop        industrial           iranian           j-dance 
     0.0030000000      0.0003333333      0.0006666667      0.0156666667      0.0146666667      0.0086666667 
           j-idol             j-pop            j-rock              jazz             k-pop              kids 
     0.0366666667      0.0040000000      0.0053333333      0.0006666667      0.0123333333      0.0280000000 
            latin            latino             malay          mandopop             metal         metalcore 
     0.0003333333      0.0010000000      0.0120000000      0.0076666667      0.0046666667      0.0100000000 
   minimal-techno               mpb           new-age             opera            pagode             party 
     0.0020000000      0.0053333333      0.0210000000      0.0066666667      0.0196666667      0.0066666667 
            piano               pop          pop-film         power-pop progressive-house        psych-rock 
     0.0093333333      0.0003333333      0.0010000000      0.0093333333      0.0013333333      0.0123333333 
             punk         punk-rock             r-n-b       rock-n-roll        rockabilly           romance 
     0.0016666667      0.0056666667      0.0036666667      0.0116666667      0.0096666667      0.0176666667 
            salsa             samba         sertanejo        show-tunes singer-songwriter               ska 
     0.0070000000      0.0080000000      0.0146666667      0.0060000000      0.0026666667      0.0133333333 
            sleep           spanish             study           swedish         synth-pop             tango 
     0.0113333333      0.0036666667      0.0246666667      0.0023333333      0.0060000000      0.0150000000 
           trance          trip-hop           turkish       world-music 
     0.0033333333      0.0090000000      0.0023333333      0.0186666667 
[1] "Frequency table sorted"

           j-idol        honky-tonk       heavy-metal          children              kids    detroit-techno 
              110               109               103                98                84                79 
            study           british     chicago-house           new-age               idm            pagode 
               74                71                67                63                61                59 
      world-music           romance          cantopop             forro         grindcore              goth 
               56                53                51                50                49                47 
       industrial          alt-rock         hard-rock             tango            grunge           iranian 
               47                46                45                45                44                44 
        sertanejo            disney          afrobeat           ambient         bluegrass               ska 
               44                43                41                41                41                40 
            k-pop        psych-rock         breakbeat             malay       rock-n-roll            groove 
               37                37                36                36                35                34 
            sleep            garage             anime            comedy            guitar               emo 
               34                33                32                32                31                30 
            happy         metalcore        rockabilly             piano         power-pop          trip-hop 
               30                30                29                28                28                27 
          j-dance              club            german             samba          acoustic          mandopop 
               26                24                24                24                23                23 
        classical       death-metal             salsa             opera             party            brazil 
               22                21                21                20                20                19 
       electronic              folk        show-tunes         synth-pop       black-metal         punk-rock 
               19                18                18                18                17                17 
           j-rock               mpb         dancehall            gospel             metal          hardcore 
               16                16                14                14                14                12 
            j-pop           electro             r-n-b           spanish            trance            indian 
               12                11                11                11                10                 9 
      alternative           hip-hop singer-songwriter           swedish           turkish             chill 
                8                 8                 8                 7                 7                 6 
   minimal-techno           country              punk             disco     drum-and-bass progressive-house 
                6                 5                 5                 4                 4                 4 
              edm            latino          pop-film             blues             dance         indie-pop 
                3                 3                 3                 2                 2                 2 
             jazz             indie             latin               pop 
                2                 1                 1                 1 
[1] "Relative frequency table (proportions) sorted"

           j-idol        honky-tonk       heavy-metal          children              kids    detroit-techno 
     0.0366666667      0.0363333333      0.0343333333      0.0326666667      0.0280000000      0.0263333333 
            study           british     chicago-house           new-age               idm            pagode 
     0.0246666667      0.0236666667      0.0223333333      0.0210000000      0.0203333333      0.0196666667 
      world-music           romance          cantopop             forro         grindcore              goth 
     0.0186666667      0.0176666667      0.0170000000      0.0166666667      0.0163333333      0.0156666667 
       industrial          alt-rock         hard-rock             tango            grunge           iranian 
     0.0156666667      0.0153333333      0.0150000000      0.0150000000      0.0146666667      0.0146666667 
        sertanejo            disney          afrobeat           ambient         bluegrass               ska 
     0.0146666667      0.0143333333      0.0136666667      0.0136666667      0.0136666667      0.0133333333 
            k-pop        psych-rock         breakbeat             malay       rock-n-roll            groove 
     0.0123333333      0.0123333333      0.0120000000      0.0120000000      0.0116666667      0.0113333333 
            sleep            garage             anime            comedy            guitar               emo 
     0.0113333333      0.0110000000      0.0106666667      0.0106666667      0.0103333333      0.0100000000 
            happy         metalcore        rockabilly             piano         power-pop          trip-hop 
     0.0100000000      0.0100000000      0.0096666667      0.0093333333      0.0093333333      0.0090000000 
          j-dance              club            german             samba          acoustic          mandopop 
     0.0086666667      0.0080000000      0.0080000000      0.0080000000      0.0076666667      0.0076666667 
        classical       death-metal             salsa             opera             party            brazil 
     0.0073333333      0.0070000000      0.0070000000      0.0066666667      0.0066666667      0.0063333333 
       electronic              folk        show-tunes         synth-pop       black-metal         punk-rock 
     0.0063333333      0.0060000000      0.0060000000      0.0060000000      0.0056666667      0.0056666667 
           j-rock               mpb         dancehall            gospel             metal          hardcore 
     0.0053333333      0.0053333333      0.0046666667      0.0046666667      0.0046666667      0.0040000000 
            j-pop           electro             r-n-b           spanish            trance            indian 
     0.0040000000      0.0036666667      0.0036666667      0.0036666667      0.0033333333      0.0030000000 
      alternative           hip-hop singer-songwriter           swedish           turkish             chill 
     0.0026666667      0.0026666667      0.0026666667      0.0023333333      0.0023333333      0.0020000000 
   minimal-techno           country              punk             disco     drum-and-bass progressive-house 
     0.0020000000      0.0016666667      0.0016666667      0.0013333333      0.0013333333      0.0013333333 
              edm            latino          pop-film             blues             dance         indie-pop 
     0.0010000000      0.0010000000      0.0010000000      0.0006666667      0.0006666667      0.0006666667 
             jazz             indie             latin               pop 
     0.0006666667      0.0003333333      0.0003333333      0.0003333333 
[1] "variable  17 : multiple_artists"

[1] "Number of modalities:  2"
[1] "Frequency table"

FALSE  TRUE 
 2927    73 
[1] "Relative frequency table (proportions)"

     FALSE       TRUE 
0.97566667 0.02433333 
[1] "Frequency table sorted"

FALSE  TRUE 
 2927    73 
[1] "Relative frequency table (proportions) sorted"

     FALSE       TRUE 
0.97566667 0.02433333 
[1] "variable  18 : tempo_cat"

[1] "Number of modalities:  12"
[1] "Frequency table"

Larghissimo       Grave Lento/Largo   Larghetto      Adagio     Andante    Moderato     Allegro      Vivace 
          0           0          10          23          96         858         422        1335         119 
     Presto Prestissimo        <NA> 
        116          17           4 
[1] "Relative frequency table (proportions)"

Larghissimo       Grave Lento/Largo   Larghetto      Adagio     Andante    Moderato     Allegro      Vivace 
0.000000000 0.000000000 0.003333333 0.007666667 0.032000000 0.286000000 0.140666667 0.445000000 0.039666667 
     Presto Prestissimo        <NA> 
0.038666667 0.005666667 0.001333333 
[1] "Frequency table sorted"

    Allegro     Andante    Moderato      Vivace      Presto      Adagio   Larghetto Prestissimo Lento/Largo 
       1335         858         422         119         116          96          23          17          10 
       <NA> Larghissimo       Grave 
          4           0           0 
[1] "Relative frequency table (proportions) sorted"

    Allegro     Andante    Moderato      Vivace      Presto      Adagio   Larghetto Prestissimo Lento/Largo 
0.445000000 0.286000000 0.140666667 0.039666667 0.038666667 0.032000000 0.007666667 0.005666667 0.003333333 
       <NA> Larghissimo       Grave 
0.001333333 0.000000000 0.000000000 
par(ask=FALSE)


#per exportar figures d'R per programa
#dev.off()

Bivariate statistics

After seeing the basic descriptive statistics of the data, we’ll do a bivariate statistics analysis. The purpose is to find relationships between: 1. Categorical vs categorical variables 2. Categorical vs numerical variables 3. Numerical vs numerical variables

Categorical vs. categorical

We examine the relationship between tempo marking and mode.

#png(file=mypath,width = 950, height = 800, units = "px")
#dev.off()
library(ggplot2)

# stacked bar chart

ggplot(dd, 
       aes(x = tempo_cat, 
           fill = mode)) + 
  geom_bar(position = "stack")

ggplot(dd, 
       aes(x = tempo_cat, 

           fill = mode)) + 
  geom_bar(position = "dodge")

ggplot(dd, 
       aes(x = tempo_cat, 

           fill = mode)) + 
Error: Incomplete expression:            fill = mode)) + 
  geom_bar(position = "stack")

ggplot(dd, 
       aes(x = tempo_cat, 
           fill = mode)) + 
  geom_bar(position = "dodge")

ggplot(dd, 
       aes(x = tempo_cat, 
           fill = mode)) + 
  geom_bar(position = "fill")

From the above bar charts, we see that while there are more songs in the major key, some tempo markings have a higher proportion of minor songs than others. Larghetto and Vivace songs are the two tempo markings that have the highest proportion of minor songs, which is interesting because Larghetto is on the slower end, and Vivace is on the faster end.

Next, we can also examine the relationship between mode and explicitness.

From the plots above: there aren’t many songs that are explicit, and it is hard to tell the relationship. The proportion of minor songs for songs that are explicit is slightly higher than major songs. However, it’s a very minimal difference.

We can also examine the relationship between track_genre and mode.

We can see there are some genres that clearly stand out that have majority minor songs. All latin songs are in the minor key. Synth-pop, turkish, trance, dancehall, romance, spanish, anime and hiphop songs are also among the top 10 genres with a high proportion of minor songs.

So, there seem to be a relationship between genre and mode.

Explicit and genre also seems to be related, as songs that are explicit tend to be from some genres. Latino songs are 100% explicit. Comedy, country, dance and some of the metal genres also tend to contain swear words.

Next we can examine the relationship between key and time signature.

The key of B has the highest proportion of minor songs. F#/Gb, E and A#/Bb also have a relatively higher percentage of minor songs.

Categorical vs numerical variables

We can also perform analysis on categorical vs numerical variables by using charts such as multiple boxplots to plot the distribution of one numerical variable given another categorical variable.

We have used the code by Dr. Karina Gibert to do an overview of the variables, and below are the interesting plots in ggplot()

First, the code below creates functions to test numerical and qualitative variables.

There are several variables we wish to assess. Our hypotheses are:

Let’s run the profiling script for the mode variable

Findings:

From the boxplot of valence vs mode, we can see that minor songs tend to have lower valence (sadder mood) than major songs. Similarly, songs in the minor key tend to have lower tempo compared to songs in the major key, although there are outliers.

Interestingly, many songs in the major key are in the key of G, C, D and A. Whereas the most popular key for minor songs are A, B and E.

For popularity, songs in the minor key have a wider range compared to major songs.

Genre vs valence.

One genre stood out when looking at highest valence: r&b. The Sleep genre has the lowest mean valence.

Next we can examine the relationship between genre and energy, by calculating the mean.

Classical songs have the least mean energy, and drum-and-bass songs have the highest mean energy.

We can also examine the relationship between genre and danceability

Energy vs mode

Minor songs actually have a higher range of energy compared to major songs, which is interesting because one would think that there would be more happy songs (typically major key) with higher energy. But this could be because many of the latin songs are in minor key.

Looking at valence vs explicitness, we see that songs that are explicit tend to have lower valence than songs that are clean.

Looking at valence vs explicitness, we see that songs that are explicit tend to have lower valence than songs that are clean.

Numerical vs Numerical

LS0tCnRpdGxlOiAiU3BvdGlmeSAtIHByZXByb2Nlc3NpbmcsIGRlc2NyaXB0aXZlIHN0YXRpc3RpY3MgYW5kIGJpdmFyaWF0ZSBzdGF0aXN0aWNzIgpvdXRwdXQ6CiAgd29yZF9kb2N1bWVudDogZGVmYXVsdAogIGh0bWxfbm90ZWJvb2s6IGRlZmF1bHQKICBodG1sX2RvY3VtZW50OgogICAgZGZfcHJpbnQ6IHBhZ2VkCi0tLQoKIyBJbnRyb2R1Y3Rpb24KCkluIHRoaXMgcHJvamVjdCwgd2UgYXJlIHVzaW5nIGEgZGF0YXNldCBvZiBzb25ncyBvbiB0aGUgbXVzaWMgc3RyZWFtaW5nIGFwcCBTcG90aWZ5LgoKVGhlIGRhdGFzZXQgY29udGFpbnMgc29uZ3Mgb24gU3BvdGlmeSBhY3Jvc3MgbXVsdGlwbGUgZ2VucmVzLCBhbmQgd2Ugd2lsbCBiZSBwZXJmb3JtaW5nIHNldmVyYWwgYW5hbHlzZXMgdG8gdGhpcyBkYXRhc2V0LCBzdWNoIGFzIGJhc2ljIGRlc2NyaXB0aXZlIGFuZCBiaXZhcmlhdGUgc3RhdGlzdGljcywgUHJpbmNpcGFsIENvbXBvbmVudCBBbmFseXNpcywgZGVjaXNpb24gdHJlZXMsIHJlZ3Jlc3Npb24sIGFuZCBjbHVzdGVyaW5nLgoKW0hlcmUgaXMgdGhlIGxpbmsgdG8gdGhlIG9yaWdpbmFsIGRhdGFzZXRdKGh0dHBzOi8vd3d3LmthZ2dsZS5jb20vZGF0YXNldHMvbWFoYXJzaGlwYW5keWEvLXNwb3RpZnktdHJhY2tzLWRhdGFzZXQpCgpGaXJzdCwgd2UgaW1wb3J0IHRoZSBkYXRhIHRvIFIgYW5kIG1ha2Ugc3VyZSBSIGlzIHJlYWRpbmcgdGhlIGRhdGEgcHJvcGVybHkuCgpgYGB7ciwgcmVzdWx0cyA9IEZBTFNFfQojIGltcG9ydGluZyByZWxldmFudCBsaWJyYXJpZXMgdG8gcGVyZm9ybSBjbGVhbmluZyBvbiB0aGUgZGF0YQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShqYW5pdG9yKQpzZXR3ZCgifi9Eb2N1bWVudHMvY2xhc3Mvc3RhdHMtZmluYWwtcHJvamVjdC8iKQojIGltcG9ydGluZyB0aGUgZGF0YSBhbmQgY2xlYW5pbmcgdGhlIG5hbWVzIGludG8gYSBzbmFrZV9jYXNlIGZvcm1hdC4KcmF3X2RhdGEgPC0gcmVhZC5jc3YoImRhdGFzZXQuY3N2IikgJT4lIGNsZWFuX25hbWVzKCkgCmBgYApUaGUgZGF0YXNldCBoYXMgMTE0LDAwMCByb3dzIGFuZCAyMSBjb2x1bW5zL3ZhcmlhYmxlcy4KCkl0IGhhcyB0aGUgZm9sbG93aW5nIHNjb3JlcyAobnVtZXJpY2FsIHZhcmlhYmxlcyk6CiogKnBvcHVsYXJpdHkqOiBUaGUgcG9wdWxhcml0eSBvZiBhIHRyYWNrIGlzIGEgdmFsdWUgYmV0d2VlbiAwIGFuZCAxMDAsIHdpdGggMTAwIGJlaW5nIHRoZSBtb3N0IHBvcHVsYXIuCi0gKmR1cmF0aW9uX21zKjogVGhlIHRyYWNrIGxlbmd0aCBpbiBtaWxsaXNlY29uZHMKLSAqZGFuY2VhYmlsaXR5KjogRGFuY2VhYmlsaXR5IGRlc2NyaWJlcyBob3cgc3VpdGFibGUgYSB0cmFjayBpcyBmb3IgZGFuY2luZyBiYXNlZCBvbiBhIGNvbWJpbmF0aW9uIG9mIG11c2ljYWwgZWxlbWVudHMgaW5jbHVkaW5nIHRlbXBvLCByaHl0aG0gc3RhYmlsaXR5LCBiZWF0IHN0cmVuZ3RoLCBhbmQgb3ZlcmFsbCByZWd1bGFyaXR5LiBBIHZhbHVlIG9mIDAuMCBpcyBsZWFzdCBkYW5jZWFibGUgYW5kIDEuMCBpcyBtb3N0IGRhbmNlYWJsZQotICplbmVyZ3kqOiBFbmVyZ3kgaXMgYSBtZWFzdXJlIGZyb20gMC4wIHRvIDEuMCBhbmQgcmVwcmVzZW50cyBhIHBlcmNlcHR1YWwgbWVhc3VyZSBvZiBpbnRlbnNpdHkgYW5kIGFjdGl2aXR5LiBUeXBpY2FsbHksIGVuZXJnZXRpYyB0cmFja3MgZmVlbCBmYXN0LCBsb3VkLCBhbmQgbm9pc3kuIEZvciBleGFtcGxlLCBkZWF0aCBtZXRhbCBoYXMgaGlnaCBlbmVyZ3ksIHdoaWxlIGEgQmFjaCBwcmVsdWRlIHNjb3JlcyBsb3cgb24gdGhlIHNjYWxlCi0gKmxvdWRuZXNzKjogVGhlIG92ZXJhbGwgbG91ZG5lc3Mgb2YgYSB0cmFjayBpbiBkZWNpYmVscyAoZEIpCi0gKnNwZWVjaGluZXNzKjogU3BlZWNoaW5lc3MgZGV0ZWN0cyB0aGUgcHJlc2VuY2Ugb2Ygc3Bva2VuIHdvcmRzIGluIGEgdHJhY2suIFRoZSBtb3JlIGV4Y2x1c2l2ZWx5IHNwZWVjaC1saWtlIHRoZSByZWNvcmRpbmcgKGUuZy4gdGFsayBzaG93LCBhdWRpbyBib29rLCBwb2V0cnkpLCB0aGUgY2xvc2VyIHRvIDEuMCB0aGUgYXR0cmlidXRlIHZhbHVlLgotICphY291c3RpY25lc3MqOiBBIGNvbmZpZGVuY2UgbWVhc3VyZSBmcm9tIDAuMCB0byAxLjAgb2Ygd2hldGhlciB0aGUgdHJhY2sgaXMgYWNvdXN0aWMuIDEuMCByZXByZXNlbnRzIGhpZ2ggY29uZmlkZW5jZSB0aGUgdHJhY2sgaXMgYWNvdXN0aWMKLSAqaW5zdHJ1bWVudGFsbmVzcyo6IFByZWRpY3RzIHdoZXRoZXIgYSB0cmFjayBjb250YWlucyBubyB2b2NhbHMuICJPb2giIGFuZCAiYWFoIiBzb3VuZHMgYXJlIHRyZWF0ZWQgYXMgaW5zdHJ1bWVudGFsIGluIHRoaXMgY29udGV4dC4gUmFwIG9yIHNwb2tlbiB3b3JkIHRyYWNrcyBhcmUgY2xlYXJseSAidm9jYWwiLiBUaGUgY2xvc2VyIHRoZSBpbnN0cnVtZW50YWxuZXNzIHZhbHVlIGlzIHRvIDEuMCwgdGhlIGdyZWF0ZXIgbGlrZWxpaG9vZCB0aGUgdHJhY2sgY29udGFpbnMgbm8gdm9jYWwgY29udGVudAotICpsaXZlbmVzcyo6IERldGVjdHMgdGhlIHByZXNlbmNlIG9mIGFuIGF1ZGllbmNlIGluIHRoZSByZWNvcmRpbmcuIEhpZ2hlciBsaXZlbmVzcyB2YWx1ZXMgcmVwcmVzZW50IGFuIGluY3JlYXNlZCBwcm9iYWJpbGl0eSB0aGF0IHRoZSB0cmFjayB3YXMgcGVyZm9ybWVkIGxpdmUuIEEgdmFsdWUgYWJvdmUgMC44IHByb3ZpZGVzIHN0cm9uZyBsaWtlbGlob29kIHRoYXQgdGhlIHRyYWNrIGlzIGxpdmUKLSAqdmFsZW5jZSo6IEEgbWVhc3VyZSBmcm9tIDAuMCB0byAxLjAgZGVzY3JpYmluZyB0aGUgbXVzaWNhbCBwb3NpdGl2ZW5lc3MgY29udmV5ZWQgYnkgYSB0cmFjay4gVHJhY2tzIHdpdGggaGlnaCB2YWxlbmNlIHNvdW5kIG1vcmUgcG9zaXRpdmUgKGUuZy4gaGFwcHksIGNoZWVyZnVsLCBldXBob3JpYyksIHdoaWxlIHRyYWNrcyB3aXRoIGxvdyB2YWxlbmNlIHNvdW5kIG1vcmUgbmVnYXRpdmUgKGUuZy4gc2FkLCBkZXByZXNzZWQsIGFuZ3J5KQotICp0ZW1wbyo6IFRoZSBvdmVyYWxsIGVzdGltYXRlZCB0ZW1wbyBvZiBhIHRyYWNrIGluIGJlYXRzIHBlciBtaW51dGUgKEJQTSkuIEluIG11c2ljYWwgdGVybWlub2xvZ3ksIHRlbXBvIGlzIHRoZSBzcGVlZCBvciBwYWNlIG9mIGEgZ2l2ZW4gcGllY2UgYW5kIGRlcml2ZXMgZGlyZWN0bHkgZnJvbSB0aGUgYXZlcmFnZSBiZWF0IGR1cmF0aW9uCgpUaGUgZGF0YXNldCBhbHNvIGhhcyB0aGUgZm9sbG93aW5nIGNhdGVnb3JpY2FsIHZhcmlhYmxlczoKLSAqZXhwbGljaXQqOiBXaGV0aGVyIG9yIG5vdCB0aGUgdHJhY2sgaGFzIGV4cGxpY2l0IGx5cmljcyAodHJ1ZSA9IHllcyBpdCBkb2VzOyBmYWxzZSA9IG5vIGl0IGRvZXMgbm90IE9SIHVua25vd24pCi0gKm1vZGUqOiBNb2RlIGluZGljYXRlcyB0aGUgbW9kYWxpdHkgKG1ham9yIG9yIG1pbm9yKSBvZiBhIHRyYWNrLCB0aGUgdHlwZSBvZiBzY2FsZSBmcm9tIHdoaWNoIGl0cyBtZWxvZGljIGNvbnRlbnQgaXMgZGVyaXZlZC4gTWFqb3IgaXMgcmVwcmVzZW50ZWQgYnkgMSBhbmQgbWlub3IgaXMgMAotICprZXkqOiBUaGUga2V5IHRoZSB0cmFjayBpcyBpbi4gSW50ZWdlcnMgbWFwIHRvIHBpdGNoZXMgdXNpbmcgc3RhbmRhcmQgUGl0Y2ggQ2xhc3Mgbm90YXRpb24uIEUuZy4gMCA9IEMsIDEgPSBD4pmvL0Tima0sIDIgPSBELCBhbmQgc28gb24uIElmIG5vIGtleSB3YXMgZGV0ZWN0ZWQsIHRoZSB2YWx1ZSBpcyAtMQotICp0cmFja19nZW5yZSo6IFRoZSBnZW5yZSBpbiB3aGljaCB0aGUgdHJhY2sgYmVsb25ncwoKSXQgYWxzbyBoYXMgdGhlIGZvbGxvd2luZyBjb2x1bW5zIHRoYXQgZGVzY3JpYmUgdGhlIHNvbmdzOgotICp0cmFja19pZCo6IFRoZSBTcG90aWZ5IElEIGZvciB0aGUgdHJhY2sKLSAqYXJ0aXN0cyo6IFRoZSBhcnRpc3RzJyBuYW1lcyB3aG8gcGVyZm9ybWVkIHRoZSB0cmFjay4gSWYgdGhlcmUgaXMgbW9yZSB0aGFuIG9uZSBhcnRpc3QsIHRoZXkgYXJlIHNlcGFyYXRlZCBieSBhIDsKLSAqYWxidW1fbmFtZSo6IFRoZSBhbGJ1bSBuYW1lIGluIHdoaWNoIHRoZSB0cmFjayBhcHBlYXJzCi0gKnRyYWNrX25hbWUqOiBOYW1lIG9mIHRoZSB0cmFjawoKTm93IHdlIGFyZSBwZXJmb3JtaW5nIHNldmVyYWwgY2hlY2tzIG9uIHRoZSBkYXRhCgpgYGB7cn0KI2RpbShyYXdfZGF0YSkKI25hbWVzKHJhd19kYXRhKQojc2FwcGx5KHJhd19kYXRhLCBjbGFzcykKYGBgCldlJ2xsIHBlcmZvcm0gdGhlIGZvbGxvd2luZyB0cmFuc2Zvcm1zIHRvIHRoZSBkYXRhIGluIG9yZGVyIHRvIHByZXBhcmUgaXQgZm9yIG91ciBhbmFseXNpczoKClNpbmNlIHNvbWUgb2YgdGhlIGNhdGVnb3JpY2FsIHZhcmlhYmxlcyAtIG1vZGUsIGtleSwgYW5kIHRpbWVfc2lnbmF0dXJlIC0gYXJlIGN1cnJlbnRseSBjb2RpZmllZCBhcyBudW1lcmljYWwsIHdlIHdpbGwgZG8gdGhlIGZvbGxvd2luZzoKMS4gKmtleSo6IFdlIHdpbGwgYmUgY29udmVydGluZyB0aGVtIGZyb20gbnVtYmVycyAwIHRvIDExIHRvIHRoZSBsZXR0ZXIgdmFsdWUgb2YgdGhlIGtleSAoQyA9IDAsIEMjID0gMSwgZXRjLikKMi4gKm1vZGUqOiBJbnN0ZWFkIG9mIDAgZm9yIG1pbm9yIGFuZCAxIGZvciBtYWpvciwgd2UnbGwgY29udmVydCB0aGVtIHRvICJtYWpvciIgYW5kICJtaW5vciIuCjMuICp0aW1lX3NpZ25hdHVyZSo6IFdlJ2xsIGNvbnZlcnQgaW50byBjaGFyYWN0ZXJzIGluc3RlYWQgb2YgbnVtZXJpYy4KCldlIGFyZSBhbHNvIGFkZGluZyAyIG1vcmUgdmFyaWFibGVzLCB3aGljaCBhcmU6CjEuICptdWx0aXBsZV9hcnRpc3RzKjogSWYgdGhlcmUgYXJlIG11bHRpcGxlIGFydGlzdHMgcGVyZm9ybWluZyB0aGUgdHJhY2ssIHRoZSBhcnRpc3RzIGNvbHVtbiB3aWxsIGNvbnRhaW4gYWxsIGFydGlzdHMgc2VwYXJhdGVkIGJ5IGEgc2VtaWNvbG9uICg7KS4gV2UnbGwgYWRkIGEgdHJ1ZSB2YWx1ZSBpbiB0aGlzIGNvbHVtbiBpZiB0aGVyZSBhcmUgbXVsdGlwbGUgYXJ0aXN0cywgYW5kIGZhbHNlIGlmIGEgc2luZ2xlIGFydGlzdC4KMi4gKnRlbXBvX2NhdCo6IHRoaXMgaXMgYSBjYXRlZ29yaWNhbCB2YXJpYWJsZSBiYXNlZCBvbiB0aGUgdGVtcG8gY29sdW1uLiBXZSdsbCB1c2UgdGhlIGJlYXRzIHBlciBtaW51dGUgdG8gZGV0ZXJtaW5lIHdoaWNoIHRlbXBvIG1hcmtpbmcgaXQgZml0cyBpbi4gVGhpcyB3aWxsIGJlIGFuIG9yZGluYWwgdmFyaWFibGUsIHdpdGggdGhlIGxldmVscyBkZWZpbmVkLgoKV2UgYXJlIGFsc28gcGVyZm9ybWluZyBzZXZlcmFsIGZpbHRlcnMgdG8gc2NvcGUgb3VyIGFuYWx5c2lzOgoxLiBGaWx0ZXIgdG8gc29uZ3MgdGhhdCBhcmUgZG9uZSBieSBwb3B1bGFyIGFydGlzdHMuIFRoaXMgaXMgZG9uZSBieSBmaW5kaW5nIHRoZSBhcnRpc3RzIHRoYXQgaGF2ZSAyMCBzb25ncyBvciBtb3JlIGFuZCBmaWx0ZXJpbmcgdG8ganVzdCB0aGUgc29uZ3MgYnkgdGhvc2UgYXJ0aXN0cy4KMi4gV2UgYWxzbyBzY29wZSB0aGUgYW5hbHlzaXMgdG8ganVzdCBzb25ncyB0aGF0IGFyZSBsZXNzIHRoYW4gMTAgbWludXRlcy4KMy4gV2UnbGwgYWxzbyByZW1vdmUgdGhlIGR1cGxpY2F0ZWQgc29uZ3MuIFRoaXMgaXMgYmVjYXVzZSBzb21lIHNvbmdzIGFyZSBsaXN0ZWQgaW4gYWxidW1zIG9yIHNpbmdsZSB2ZXJzaW9ucy4gVGhpcyBpcyBkb25lIGJ5IHJlbW92aW5nIHNvbmdzIHRoYXQgaGF2ZSB0aGUgc2FtZSB2YXJpYWJsZSBpbiB0aGUgdHJhY2tfbmFtZSBhbmQgYXJ0aXN0cyBjb2x1bW5zLgo0LiBXZSBhbHNvIHNhbXBsZSB0aGUgZGF0YSB0byBqdXN0IDMsMDAwIHJvd3Mvc29uZ3MuIFRoaXMgaXMgZG9uZSBieSByYW5kb20gc2FtcGxpbmcgdXNpbmcgdGhlIGBzYW1wbGVfbigpYCBmdW5jdGlvbi4KCkZpbmFsbHksIHdlJ2xsIGp1c3Qgc2VsZWN0IHRoZSBjb2x1bW5zIHRoYXQgYXJlIHJlbGV2YW50IHRvIHVzIGluIG91ciBhbmFseXNpcywgYW5kIHJlbW92ZSB0aGUgZGVzY3JpcHRpdmUgY29sdW1ucywgdHJhY2tfaWQsIGFydGlzdHMsIGFsYnVtX25hbWUsIGFuZCB0cmFja19uYW1lLgoKYGBge3IsIHJlc3VsdHMgPSBGQUxTRX0KIyBjcmVhdGluZyBhIGxpc3Qgb2Yga2V5cyBmcm9tIEMgdG8gQgprZXlfYWxwaGEgPC0gYygnQycsJ0MjL0RiJywnRCcsJ0QjL0ViJywnRScsJ0YnLCdGIy9HYicsJ0cnLCdHIy9BYicsJ0EnLCdBIy9CYicsJ0InKQoKIyBjcmVhdGluZyBhIG5ldyBkZiBmb3IgbWFwcGluZyBrZXlzCmtleV9tYXAgPC0gZGF0YS5mcmFtZShrZXkgPSBjKDA6MTEpLAogICAgICAgICAgICAgICAgICAgICAga2V5X2FscGhhID0ga2V5X2FscGhhKQoKZGF0YSA8LSByYXdfZGF0YSAlPiUKICBmdWxsX2pvaW4oa2V5X21hcCwgImtleSIpICU+JSAKICBtdXRhdGUobW9kZSA9IHN0cl9yZXBsYWNlKGFzLmNoYXJhY3Rlcihtb2RlKSwgIjAiLCAibWlub3IiKSwKICAgICAgICAgbW9kZSA9IHN0cl9yZXBsYWNlKGFzLmNoYXJhY3Rlcihtb2RlKSwgIjEiLCAibWFqb3IiKSwKICAgICAgICAgdGltZV9zaWduYXR1cmUgPSBhcy5jaGFyYWN0ZXIodGltZV9zaWduYXR1cmUpLAogICAgICAgICAjIGNvbnZlcnRpbmcga2V5cyB0byBhbHBoYWJldAogICAgICAgICBrZXkgPSBrZXlfYWxwaGEsCiAgICAgICAgICMgYWRkaW5nIGEgY29sdW1uIGZvciB3aGV0aGVyIHRoZSBhcnRpc3QgaXMgb25lIG9yIG11bHRpcGxlLiBUcnVlIGZvciBNdWx0aXBsZSwgZmFsc2UgZm9yIHNpbmdsZQogICAgICAgICBtdWx0aXBsZV9hcnRpc3RzID0gZ3JlcGwoIjsiLCBhcnRpc3RzKQogICAgICAgICApICU+JSAKICBzZWxlY3QoLTEsIC0yMikgJT4lCiAgIyByZW1vdmluZyBkdXBsaWNhdGVzIGluIHNvbmdzLCBiZWNhdXNlIHNvbWUgdHJhY2tzIGFyZSBpbiBtdWx0aXBsZSBhbGJ1bXMKICBkaXN0aW5jdCh0cmFja19uYW1lLCBhcnRpc3RzLCAua2VlcF9hbGwgPSBUUlVFKQoKIyBmaW5kaW5nIHRoZSBwb3B1bGFyIGFydGlzdHMsIHdpdGggbW9yZSB0aGFuIDIwIHNvbmdzIGxpc3RlZC4KcG9wdWxhcl9hcnRpc3RzIDwtIGRhdGEgJT4lIGdyb3VwX2J5KGFydGlzdHMpICU+JSAKICBzdW1tYXJpemUoY291bnQgPSBuKCkpICU+JSAKICBmaWx0ZXIoY291bnQgPj0gMjApIAoKZmlsdGVyZWQgPC0gZGF0YSAlPiUgZmlsdGVyKGFydGlzdHMgJWluJSBwb3B1bGFyX2FydGlzdHMkYXJ0aXN0cykgJT4lIAogIGZpbHRlcihkdXJhdGlvbl9tcyA8PSA2MDAwMDApICU+JQogICNyZW1vdmluZyB0aGUgdHJhY2tfaWQsIHRpdGxlLCBhcnRpc3RzLCBhbGJ1bXMgYmVjYXVzZSBpdCdzIG5vdCBuZWVkZWQuCiAgc2VsZWN0KDU6MjEpICU+JQogIG11dGF0ZSgKICAjIGFkZGluZyBhbiBvcmRpbmFsIHZhcmlhYmxlIGZvciB0ZW1wbwogIHRlbXBvX2NhdCA9IGN1dCh0ZW1wbywKICAgICAgICAgICAgICBicmVha3M9YygwLCAyMCwgNDAsIDYwLCA2NiwgNzYsIDEwOCwgMTIwLCAxNjgsIDE3NiwgMjAwLCAxMDAwKSwKICAgICAgICAgICAgICBsYWJlbHM9YygnTGFyZ2hpc3NpbW8nLCdHcmF2ZScsJ0xlbnRvL0xhcmdvJywnTGFyZ2hldHRvJywnQWRhZ2lvJywnQW5kYW50ZScsJ01vZGVyYXRvJywnQWxsZWdybycsJ1ZpdmFjZScsJ1ByZXN0bycsJ1ByZXN0aXNzaW1vJykpCikKCiMgcmFuZG9tIHNhbXBsaW5nIHRoZSBkYXRhIHRvIGp1c3QgMzAwMCBzb25ncwpzZXQuc2VlZCgxKQpkZCA8LSBmaWx0ZXJlZCAlPiUgc2FtcGxlX24oMzAwMCkKCiMgYXR0YWNoaW5nIHRoZSBjb2x1bW4gbmFtZXMKYXR0YWNoKGRkKQoKIyBmb3Igb25lLXRpbWUgZXhwb3J0aW5nIGZvciBvdGhlciBhbmFseXNpcwojIGRkICU+JSB3cml0ZV9jc3YoImNsZWFuZWRkYXRhLmNzdiIpCmBgYAoKIyBEZXNjcmlwdGl2ZSBTdGF0aXN0aWNzCgoKCgpgYGB7cn0KbjwtZGltKGRkKVsxXQpLPC1kaW0oZGQpWzJdCgpkZXNjcmlwdGl2YTwtZnVuY3Rpb24oWCwgbm9tKXsKICBpZiAoIShpcy5udW1lcmljKFgpIHx8IGNsYXNzKFgpPT0iRGF0ZSIpKXsgCiAgICBmcmVjczwtdGFibGUoYXMuZmFjdG9yKFgpLCB1c2VOQT0iaWZhbnkiKQogICAgcHJvcG9ydGlvbnM8LWZyZWNzL24KICAgICNvam8sIGRlY2lkaXIgc2kgY2FsY3VsYXIgcG9yY2VudGFnZXMgY29uIG8gc2luIG1pc3NpbmcgdmFsdWVzCiAgICBwaWUoZnJlY3MsIGNleD0wLjYsIG1haW49cGFzdGUoIlBpZSBvZiIsIG5vbSkpCiAgICBiYXJwbG90KGZyZWNzLCBsYXM9MywgY2V4Lm5hbWVzPTAuNywgbWFpbj1wYXN0ZSgiQmFycGxvdCBvZiIsIG5vbSksIGNvbD1saXN0T2ZDb2xvcnMpCiAgICBwcmludChwYXN0ZSgiTnVtYmVyIG9mIG1vZGFsaXRpZXM6ICIsIGxlbmd0aChmcmVjcykpKQogICAgcHJpbnQoIkZyZXF1ZW5jeSB0YWJsZSIpCiAgICBwcmludChmcmVjcykKICAgIHByaW50KCJSZWxhdGl2ZSBmcmVxdWVuY3kgdGFibGUgKHByb3BvcnRpb25zKSIpCiAgICBwcmludChwcm9wb3J0aW9ucykKICAgIHByaW50KCJGcmVxdWVuY3kgdGFibGUgc29ydGVkIikKICAgIHByaW50KHNvcnQoZnJlY3MsIGRlY3JlYXNpbmc9VFJVRSkpCiAgICBwcmludCgiUmVsYXRpdmUgZnJlcXVlbmN5IHRhYmxlIChwcm9wb3J0aW9ucykgc29ydGVkIikKICAgIHByaW50KHNvcnQocHJvcG9ydGlvbnMsIGRlY3JlYXNpbmc9VFJVRSkpCiAgIH1lbHNlewogICAgIGlmKGNsYXNzKFgpPT0iRGF0ZSIpewogICAgICAgcHJpbnQoc3VtbWFyeShYKSkKICAgICAgIHByaW50KHNkKFgpKQogICAgICAgI2RlY2lkZSBicmVha3M6IHdlZWtzLCBtb250aHMsIHF1YXJ0ZXJzLi4uCiAgICAgICBoaXN0KFgsYnJlYWtzPSJ3ZWVrcyIpCiAgICAgfWVsc2V7CiAgICAgICBoaXN0KFgsIG1haW49cGFzdGUoIkhpc3RvZ3JhbSBvZiIsIG5vbSkpCiAgICAgICBib3hwbG90KFgsIGhvcml6b250YWw9VFJVRSwgbWFpbj1wYXN0ZSgiQm94cGxvdCBvZiIsbm9tKSkKICAgICAgIHByaW50KCJFeHRlbmRlZCBTdW1tYXJ5IFN0YXRpc3RpY3MiKQogICAgICAgcHJpbnQoc3VtbWFyeShYKSkKICAgICAgIHByaW50KHBhc3RlKCJzZDogIiwgc2QoWCwgbmEucm09VFJVRSkpKQogICAgICAgcHJpbnQocGFzdGUoInZjOiAiLCBzZChYLCBuYS5ybT1UUlVFKS9tZWFuKFgsIG5hLnJtPVRSVUUpKSkKICAgICAgfQogICB9Cn0KCmRhdGFzZXQ8LWRkCmFjdGl2ZXM8LWMoMTpLKQpjb2xEYXRlPC0xCmlmIChkYXRhc2V0PT0icGxhdGphRGFybyIpCiAge2RkWyxjb2xEYXRlXTwtYXMuRGF0ZShkZFssIGNvbERhdGVdLCBmb3JtYXQ9IiVkLyVtLyV5ICVoOiVtOiVzIikKICAgYWN0aXZlczwtYygzOjQ0KQogICB9CgpsaXN0T2ZDb2xvcnM8LXJhaW5ib3coMzkpCgpwYXIoYXNrPUZBTFNFKQoKZm9yKGsgaW4gYWN0aXZlcyl7CiAgcHJpbnQocGFzdGUoInZhcmlhYmxlICIsIGssICI6IiwgbmFtZXMoZGQpW2tdICkpCiAgZGVzY3JpcHRpdmEoZGRbLGtdLCBuYW1lcyhkZClba10pCn0KcGFyKGFzaz1GQUxTRSkKCiNwZXIgZXhwb3J0YXIgZmlndXJlcyBkJ1IgcGVyIHByb2dyYW1hCiNkZXYub2ZmKCkKI3BuZyhmaWxlPW15cGF0aCx3aWR0aCA9IDk1MCwgaGVpZ2h0ID0gODAwLCB1bml0cyA9ICJweCIpCiNkZXYub2ZmKCkKYGBgCgoKIyBCaXZhcmlhdGUgc3RhdGlzdGljcwoKQWZ0ZXIgc2VlaW5nIHRoZSBiYXNpYyBkZXNjcmlwdGl2ZSBzdGF0aXN0aWNzIG9mIHRoZSBkYXRhLCB3ZSdsbCBkbyBhIGJpdmFyaWF0ZSBzdGF0aXN0aWNzIGFuYWx5c2lzLiBUaGUgcHVycG9zZSBpcyB0byBmaW5kIHJlbGF0aW9uc2hpcHMgYmV0d2VlbjoKMS4gQ2F0ZWdvcmljYWwgdnMgY2F0ZWdvcmljYWwgdmFyaWFibGVzCjIuIENhdGVnb3JpY2FsIHZzIG51bWVyaWNhbCB2YXJpYWJsZXMKMy4gTnVtZXJpY2FsIHZzIG51bWVyaWNhbCB2YXJpYWJsZXMKCiMjIENhdGVnb3JpY2FsIHZzLiBjYXRlZ29yaWNhbAoKV2UgZXhhbWluZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gdGVtcG8gbWFya2luZyBhbmQgbW9kZS4KCmBgYHtyfQpsaWJyYXJ5KGdncGxvdDIpCgojIHN0YWNrZWQgYmFyIGNoYXJ0CgpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSB0ZW1wb19jYXQsIAogICAgICAgICAgIGZpbGwgPSBtb2RlKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIpCgpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSB0ZW1wb19jYXQsIAogICAgICAgICAgIGZpbGwgPSBtb2RlKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpCgpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSB0ZW1wb19jYXQsIAogICAgICAgICAgIGZpbGwgPSBtb2RlKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJmaWxsIikKYGBgCkZyb20gdGhlIGFib3ZlIGJhciBjaGFydHMsIHdlIHNlZSB0aGF0IHdoaWxlIHRoZXJlIGFyZSBtb3JlIHNvbmdzIGluIHRoZSBtYWpvciBrZXksIHNvbWUgdGVtcG8gbWFya2luZ3MgaGF2ZSBhIGhpZ2hlciBwcm9wb3J0aW9uIG9mIG1pbm9yIHNvbmdzIHRoYW4gb3RoZXJzLiBMYXJnaGV0dG8gYW5kIFZpdmFjZSBzb25ncyBhcmUgdGhlIHR3byB0ZW1wbyBtYXJraW5ncyB0aGF0IGhhdmUgdGhlIGhpZ2hlc3QgcHJvcG9ydGlvbiBvZiBtaW5vciBzb25ncywgd2hpY2ggaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSBMYXJnaGV0dG8gaXMgb24gdGhlIHNsb3dlciBlbmQsIGFuZCBWaXZhY2UgaXMgb24gdGhlIGZhc3RlciBlbmQuCgpOZXh0LCB3ZSBjYW4gYWxzbyBleGFtaW5lIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBtb2RlIGFuZCBleHBsaWNpdG5lc3MuCgpgYGB7cn0KIyBzdGFja2VkIGJhciBjaGFydAoKZ2dwbG90KGRkLCAKICAgICAgIGFlcyh4ID0gZXhwbGljaXQsIAogICAgICAgICAgIGZpbGwgPSBtb2RlKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJzdGFjayIpCgpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSBleHBsaWNpdCwgCiAgICAgICAgICAgZmlsbCA9IG1vZGUpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikKCmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IGV4cGxpY2l0LCAKICAgICAgICAgICBmaWxsID0gbW9kZSkpICsgCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAiZmlsbCIpCmBgYApGcm9tIHRoZSBwbG90cyBhYm92ZTogdGhlcmUgYXJlbid0IG1hbnkgc29uZ3MgdGhhdCBhcmUgZXhwbGljaXQsIGFuZCBpdCBpcyBoYXJkIHRvIHRlbGwgdGhlIHJlbGF0aW9uc2hpcC4gVGhlIHByb3BvcnRpb24gb2YgbWlub3Igc29uZ3MgZm9yIHNvbmdzIHRoYXQgYXJlIGV4cGxpY2l0IGlzIHNsaWdodGx5IGhpZ2hlciB0aGFuIG1ham9yIHNvbmdzLiBIb3dldmVyLCBpdCdzIGEgdmVyeSBtaW5pbWFsIGRpZmZlcmVuY2UuCgpXZSBjYW4gYWxzbyBleGFtaW5lIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiB0cmFja19nZW5yZSBhbmQgbW9kZS4KCmBgYHtyfQojIHN0YWNrZWQgYmFyIGNoYXJ0CmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IHRyYWNrX2dlbnJlLCAKICAgICAgICAgICBmaWxsID0gbW9kZSkpICsgCiAgZ2VvbV9iYXIocG9zaXRpb24gPSAic3RhY2siKSArIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKQoKZ2dwbG90KGRkLCAKICAgICAgIGFlcyh4ID0gdHJhY2tfZ2VucmUsIAogICAgICAgICAgIGZpbGwgPSBtb2RlKSkgKyAKICBnZW9tX2Jhcihwb3NpdGlvbiA9ICJkb2RnZSIpICsgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpCgpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSB0cmFja19nZW5yZSwgCiAgICAgICAgICAgZmlsbCA9IG1vZGUpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgICB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSBzaXplCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNSwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSBoZWlnaHQKICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgwLjUsICdjbScpLCAjY2hhbmdlIGxlZ2VuZCBrZXkgd2lkdGgKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT01KSwgI2NoYW5nZSBsZWdlbmQgdGl0bGUgZm9udCBzaXplCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT01KSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKSAKCiMgZ2V0dGluZyB0aGUgcmVzdWx0cyBvZiB0aGUgcHJvcG9ydGlvbiBiYXIgY2hhcnQgaW4gYSB0YWJsZQpkZCAlPiUgZ3JvdXBfYnkodHJhY2tfZ2VucmUsIG1vZGUpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIG11dGF0ZShmcmVxID0gbiAvIHN1bShuKSkgJT4lIAogIGZpbHRlcihtb2RlID09ICJtaW5vciIpICU+JSAKICBhcnJhbmdlKGRlc2MoZnJlcSkpCgogIApgYGAKV2UgY2FuIHNlZSB0aGVyZSBhcmUgc29tZSBnZW5yZXMgdGhhdCBjbGVhcmx5IHN0YW5kIG91dCB0aGF0IGhhdmUgbWFqb3JpdHkgbWlub3Igc29uZ3MuCkFsbCBsYXRpbiBzb25ncyBhcmUgaW4gdGhlIG1pbm9yIGtleS4gU3ludGgtcG9wLCB0dXJraXNoLCB0cmFuY2UsIGRhbmNlaGFsbCwgcm9tYW5jZSwgc3BhbmlzaCwgYW5pbWUgYW5kIGhpcGhvcCBzb25ncyBhcmUgYWxzbyBhbW9uZyB0aGUgdG9wIDEwIGdlbnJlcyB3aXRoIGEgaGlnaCBwcm9wb3J0aW9uIG9mIG1pbm9yIHNvbmdzLgoKU28sIHRoZXJlIHNlZW0gdG8gYmUgYSByZWxhdGlvbnNoaXAgYmV0d2VlbiBnZW5yZSBhbmQgbW9kZS4KCmBgYHtyfQojIHN0YWNrZWQgYmFyIGNoYXJ0CmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IHRyYWNrX2dlbnJlLCAKICAgICAgICAgICBmaWxsID0gZXhwbGljaXQpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIikgKyBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkKCmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IHRyYWNrX2dlbnJlLCAKICAgICAgICAgICBmaWxsID0gZXhwbGljaXQpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikgKyBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkKCmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IHRyYWNrX2dlbnJlLCAKICAgICAgICAgICBmaWxsID0gZXhwbGljaXQpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKSArIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKSArCiAgICB0aGVtZShsZWdlbmQua2V5LnNpemUgPSB1bml0KDAuNSwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSBzaXplCiAgICAgICAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNSwgJ2NtJyksICNjaGFuZ2UgbGVnZW5kIGtleSBoZWlnaHQKICAgICAgICBsZWdlbmQua2V5LndpZHRoID0gdW5pdCgwLjUsICdjbScpLCAjY2hhbmdlIGxlZ2VuZCBrZXkgd2lkdGgKICAgICAgICBsZWdlbmQudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZT01KSwgI2NoYW5nZSBsZWdlbmQgdGl0bGUgZm9udCBzaXplCiAgICAgICAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZT01KSkgKwogIHRoZW1lKHRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpKSAKCiMgZ2V0dGluZyB0aGUgcmVzdWx0cyBvZiB0aGUgcHJvcG9ydGlvbiBiYXIgY2hhcnQgaW4gYSB0YWJsZQpkZCAlPiUgZ3JvdXBfYnkodHJhY2tfZ2VucmUsIGV4cGxpY2l0KSAlPiUgCiAgc3VtbWFyaXNlKG4gPSBuKCkpICU+JSAKICBtdXRhdGUoZnJlcSA9IG4gLyBzdW0obikpICU+JSAKICBmaWx0ZXIoZXhwbGljaXQgPT0gIlRydWUiKSAlPiUgCiAgYXJyYW5nZShkZXNjKGZyZXEpKQpgYGAKCkV4cGxpY2l0IGFuZCBnZW5yZSBhbHNvIHNlZW1zIHRvIGJlIHJlbGF0ZWQsIGFzIHNvbmdzIHRoYXQgYXJlIGV4cGxpY2l0IHRlbmQgdG8gYmUgZnJvbSBzb21lIGdlbnJlcy4KTGF0aW5vIHNvbmdzIGFyZSAxMDAlIGV4cGxpY2l0LiBDb21lZHksIGNvdW50cnksIGRhbmNlIGFuZCBzb21lIG9mIHRoZSBtZXRhbCBnZW5yZXMgYWxzbyB0ZW5kIHRvIGNvbnRhaW4gc3dlYXIgd29yZHMuCgpOZXh0IHdlIGNhbiBleGFtaW5lIHRoZSByZWxhdGlvbnNoaXAgYmV0d2VlbiBrZXkgYW5kIHRpbWUgc2lnbmF0dXJlLgoKYGBge3J9CiMgc3RhY2tlZCBiYXIgY2hhcnQKCmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IGtleSwgCiAgICAgICAgICAgZmlsbCA9IG1vZGUpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gInN0YWNrIikKCmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IGtleSwgCiAgICAgICAgICAgZmlsbCA9IG1vZGUpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImRvZGdlIikKCmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IGtleSwgCiAgICAgICAgICAgZmlsbCA9IG1vZGUpKSArIAogIGdlb21fYmFyKHBvc2l0aW9uID0gImZpbGwiKQoKIyBnZXR0aW5nIHRoZSByZXN1bHRzIG9mIHRoZSBwcm9wb3J0aW9uIGJhciBjaGFydCBpbiBhIHRhYmxlCmRkICU+JSBncm91cF9ieShrZXksIG1vZGUpICU+JSAKICBzdW1tYXJpc2UobiA9IG4oKSkgJT4lIAogIG11dGF0ZShmcmVxID0gbiAvIHN1bShuKSkgJT4lIAogIGZpbHRlcihtb2RlID09ICJtaW5vciIpICU+JSAKICBhcnJhbmdlKGRlc2MoZnJlcSkpCmBgYApUaGUga2V5IG9mIEIgaGFzIHRoZSBoaWdoZXN0IHByb3BvcnRpb24gb2YgbWlub3Igc29uZ3MuIEYjL0diLCBFIGFuZCBBIy9CYiBhbHNvIGhhdmUgYSByZWxhdGl2ZWx5IGhpZ2hlciBwZXJjZW50YWdlIG9mIG1pbm9yIHNvbmdzLgoKCgojIyBDYXRlZ29yaWNhbCB2cyBudW1lcmljYWwgdmFyaWFibGVzCgpXZSBjYW4gYWxzbyBwZXJmb3JtIGFuYWx5c2lzIG9uIGNhdGVnb3JpY2FsIHZzIG51bWVyaWNhbCB2YXJpYWJsZXMgYnkgdXNpbmcgY2hhcnRzIHN1Y2ggYXMgbXVsdGlwbGUgYm94cGxvdHMgdG8gcGxvdCB0aGUgZGlzdHJpYnV0aW9uIG9mIG9uZSBudW1lcmljYWwgdmFyaWFibGUgZ2l2ZW4gYW5vdGhlciBjYXRlZ29yaWNhbCB2YXJpYWJsZS4KCldlIGhhdmUgdXNlZCB0aGUgY29kZSBieSBEci4gS2FyaW5hIEdpYmVydCB0byBkbyBhbiBvdmVydmlldyBvZiB0aGUgdmFyaWFibGVzLCBhbmQgYmVsb3cgYXJlIHRoZSBpbnRlcmVzdGluZyBwbG90cyBpbiBgZ2dwbG90KClgCgpGaXJzdCwgdGhlIGNvZGUgYmVsb3cgY3JlYXRlcyBmdW5jdGlvbnMgdG8gdGVzdCBudW1lcmljYWwgYW5kIHF1YWxpdGF0aXZlIHZhcmlhYmxlcy4KCmBgYHtyfQojQ2FsY3VsYSBlbHMgdmFsb3IgdGVzdCBkZSBsYSB2YXJpYWJsZSBYbnVtIHBlciB0b3RlcyBsZXMgbW9kYWxpdGF0cyBkZWwgZmFjdG9yIFAKVmFsb3JUZXN0WG51bSA8LSBmdW5jdGlvbihYbnVtLFApewogICNmcmVxIGRpcyBvZiBmYWMKICBuayA8LSBhcy52ZWN0b3IodGFibGUoUCkpOyAKICBuIDwtIHN1bShuayk7IAogICNtaXRqYW5lcyB4IGdydXBzCiAgeGsgPC0gdGFwcGx5KFhudW0sUCxtZWFuKTsKICAjdmFsb3JzIHRlc3QKICB0eGsgPC0gKHhrLW1lYW4oWG51bSkpLyhzZChYbnVtKSpzcXJ0KChuLW5rKS8obipuaykpKTsgCiAgI3AtdmFsdWVzCiAgcHhrIDwtIHB0KHR4ayxuLTEsbG93ZXIudGFpbD1GKTsKICBmb3IoYyBpbiAxOmxlbmd0aChsZXZlbHMoYXMuZmFjdG9yKFApKSkpe2lmIChweGtbY10+MC41KXtweGtbY108LTEtcHhrW2NdfX0KICByZXR1cm4gKHB4aykKfQoKVmFsb3JUZXN0WHF1YWxpIDwtIGZ1bmN0aW9uKFAsWHF1YWxpKXsKICB0YXVsYSA8LSB0YWJsZShQLFhxdWFsaSk7CiAgbiA8LSBzdW0odGF1bGEpOyAKICBwayA8LSBhcHBseSh0YXVsYSwxLHN1bSkvbjsKICBwaiA8LSBhcHBseSh0YXVsYSwyLHN1bSkvbjsKICBwZiA8LSB0YXVsYS8obipwayk7CiAgcGptIDwtIG1hdHJpeChkYXRhPXBqLG5yb3c9ZGltKHBmKVsxXSxuY29sPWRpbShwZilbMl0sIGJ5cm93PVRSVUUpOyAgICAgIAogIGRwZiA8LSBwZiAtIHBqbTsgCiAgZHZ0IDwtIHNxcnQoKCgxLXBrKS8obipwaykpJSoldChwaiooMS1waikpKTsgCiAgI2kgaGkgaGEgZGl2aXNpb25zIGlndWFscyBhIDAgZG9uYSBOQSBpIG5vIGZ1bmNpb25hCiAgemtqIDwtIGRwZgogIHpraltkcGYhPTBdPC1kcGZbZHBmIT0wXS9kdnRbZHBmIT0wXTsgCiAgcHpraiA8LSBwbm9ybSh6a2osbG93ZXIudGFpbD1GKTsKICBmb3IoYyBpbiAxOmxlbmd0aChsZXZlbHMoYXMuZmFjdG9yKFApKSkpe2ZvciAocyBpbiAxOmxlbmd0aChsZXZlbHMoWHF1YWxpKSkpe2lmIChwemtqW2Msc10+IDAuNSl7cHpraltjLHNdPC0xLSBwemtqW2Msc119fX0KICByZXR1cm4gKGxpc3Qocm93cGY9cGYsdnRlc3Q9emtqLHB2YWw9cHpraikpCn0KYGBgCgpUaGVyZSBhcmUgc2V2ZXJhbCB2YXJpYWJsZXMgd2Ugd2lzaCB0byBhc3Nlc3MuIE91ciBoeXBvdGhlc2VzIGFyZToKLSAKCkxldCdzIHJ1biB0aGUgcHJvZmlsaW5nIHNjcmlwdCBmb3IgdGhlIG1vZGUgdmFyaWFibGUKCmBgYHtyfQojRGF0YSBpcyByZWZlcnJlZCB0byBhcyAiZGFkZXMiIGluIHRoZSBmb2xsb3dpbmcgY29kZQoKZGFkZXM8LWRkCks8LWRpbShkYWRlcylbMl0KI3Bhcihhc2s9VFJVRSkKCiNQIG11c3QgY29udGFpbiB0aGUgY2xhc3MgdmFyaWFibGUKUDwtZGQkbW9kZQpuYW1lUDwtIm1vZGUiCgoKCm5jPC1sZW5ndGgobGV2ZWxzKGFzLmZhY3RvcihQKSkpCnB2YWxrIDwtIG1hdHJpeChkYXRhPTAsbnJvdz1uYyxuY29sPUssIGRpbW5hbWVzPWxpc3QobGV2ZWxzKFApLG5hbWVzKGRhZGVzKSkpCm5hbWVQPC0ibW9kZSIKbjwtZGltKGRhZGVzKVsxXQoKZm9yKGsgaW4gMTpLKXsKICBpZiAoaXMubnVtZXJpYyhkYWRlc1ssa10pKXsgCiAgICBwcmludChwYXN0ZSgiQW5hbHlzaXMgYnkgY2xhc3Mgb2YgdGhlIFZhcmlhYmxlOiIsIG5hbWVzKGRhZGVzKVtrXSkpCiAgICAKICAgIGJveHBsb3QoZGFkZXNbLGtdflAsIG1haW49cGFzdGUoIkJveHBsb3Qgb2YiLCBuYW1lcyhkYWRlcylba10sICJ2cyIsIG5hbWVQICksIGhvcml6b250YWw9VFJVRSkKICAgIAogICAgYmFycGxvdCh0YXBwbHkoZGFkZXNbW2tdXSwgUCwgbWVhbiksbWFpbj1wYXN0ZSgiTWVhbnMgb2YiLCBuYW1lcyhkYWRlcylba10sICJieSIsIG5hbWVQICkpCiAgICBhYmxpbmUoaD1tZWFuKGRhZGVzW1trXV0pKQogICAgbGVnZW5kKDAsbWVhbihkYWRlc1tba11dKSwiZ2xvYmFsIG1lYW4iLGJ0eT0ibiIpCiAgICBwcmludCgiU3RhdGlzdGljcyBieSBncm91cHM6IikKICAgIGZvcihzIGluIGxldmVscyhhcy5mYWN0b3IoUCkpKSB7cHJpbnQoc3VtbWFyeShkYWRlc1tQPT1zLGtdKSl9CiAgICBvPC1vbmV3YXkudGVzdChkYWRlc1ssa11+UCkKICAgIHByaW50KHBhc3RlKCJwLXZhbHVlQU5PVkE6IiwgbyRwLnZhbHVlKSkKICAgIGt3PC1rcnVza2FsLnRlc3QoZGFkZXNbLGtdflApCiAgICBwcmludChwYXN0ZSgicC12YWx1ZSBLcnVza2FsLVdhbGxpczoiLCBrdyRwLnZhbHVlKSkKICAgIHB2YWxrWyxrXTwtVmFsb3JUZXN0WG51bShkYWRlc1ssa10sIFApCiAgICBwcmludCgicC12YWx1ZXMgVmFsb3JzVGVzdDogIikKICAgIHByaW50KHB2YWxrWyxrXSkgICAgICAKICB9ZWxzZXsKICAgIGlmKGNsYXNzKGRkWyxrXSk9PSJEYXRlIil7CiAgICAgIHByaW50KHN1bW1hcnkoZGRbLGtdKSkKICAgICAgcHJpbnQoc2QoZGRbLGtdKSkKICAgICAgI2RlY2lkZSBicmVha3M6IHdlZWtzLCBtb250aHMsIHF1YXJ0ZXJzLi4uCiAgICAgIGhpc3QoZGRbLGtdLGJyZWFrcz0id2Vla3MiKQogICAgfWVsc2V7CiAgICAgICNxdWFsaXRhdGl2ZXMKICAgICAgcHJpbnQocGFzdGUoIlZhcmlhYmxlIiwgbmFtZXMoZGFkZXMpW2tdKSkKICAgICAgdGFibGU8LXRhYmxlKFAsZGFkZXNbLGtdKQogICAgICAjICAgcHJpbnQoIkNyb3NzLXRhYmxlIikKICAgICAgIyAgIHByaW50KHRhYmxlKQogICAgICByb3dwZXJjPC1wcm9wLnRhYmxlKHRhYmxlLDEpCiAgICAgIAogICAgICBjb2xwZXJjPC1wcm9wLnRhYmxlKHRhYmxlLDIpCiAgICAgICMgIHByaW50KCJEaXN0cmlidWNpb25zIGNvbmRpY2lvbmFkZXMgYSBmaWxlcyIpCiAgICAgICMgcHJpbnQocm93cGVyYykKICAgICAgCiAgICAgICNvam8gcG9ycXVlIHNpIGxhIHZhcmlhYmxlIGVzIHRydWUgbyBmYWxzZSBsYSBpZGVudGlmaWNhIGFtYiBlbCB0aXB1cyBMb2dpY2FsIGkKICAgICAgI2FxdWVzdCBubyB0ZSBsZXZlbHMsIHBvciB0YW50bywgY29lcnRpb24gcHJldmVudGl2YQogICAgICAKICAgICAgZGFkZXNbLGtdPC1hcy5mYWN0b3IoZGFkZXNbLGtdKQogICAgICAKICAgICAgCiAgICAgIG1hcmcgPC0gdGFibGUoYXMuZmFjdG9yKFApKS9uCiAgICAgIHByaW50KGFwcGVuZCgiQ2F0ZWdvcmllcz0iLGxldmVscyhhcy5mYWN0b3IoZGFkZXNbLGtdKSkpKQogICAgICAKICAgICAgI2Zyb20gbmV4dCBwbG90cywgc2VsZWN0IG9uZSBvZiB0aGVtIGFjY29yZGluZyB0byB5b3VyIHByYWN0aWNhbCBjYXNlCiAgICAgIAogICAgICAjd2l0aCBsZWdlbmQKICAgICAgcGxvdChtYXJnLHR5cGU9ImwiLHlsaW09YygwLDEpLG1haW49cGFzdGUoIlByb3AuIG9mIHBvcyAmIG5lZyBieSIsbmFtZXMoZGFkZXMpW2tdKSkKICAgICAgcGFsZXRhPC1yYWluYm93KGxlbmd0aChsZXZlbHMoZGFkZXNbLGtdKSkpCiAgICAgIGZvcihjIGluIDE6bGVuZ3RoKGxldmVscyhkYWRlc1ssa10pKSl7bGluZXMoY29scGVyY1ssY10sY29sPXBhbGV0YVtjXSkgfQogICAgICBsZWdlbmQoInRvcHJpZ2h0IiwgbGV2ZWxzKGRhZGVzWyxrXSksIGNvbD1wYWxldGEsIGx0eT0yLCBjZXg9MC42KQogICAgICAKICAgICAgI2NvbmRpY2lvbmFkZXMgYSBjbGFzc2VzCiAgICAgICN3aXRoIGxlZ2VuZAogICAgICBwbG90KG1hcmcsdHlwZT0ibiIseWxpbT1jKDAsMSksbWFpbj1wYXN0ZSgiUHJvcC4gb2YgcG9zICYgbmVnIGJ5IixuYW1lcyhkYWRlcylba10pKQogICAgICBwYWxldGE8LXJhaW5ib3cobGVuZ3RoKGxldmVscyhkYWRlc1ssa10pKSkKICAgICAgZm9yKGMgaW4gMTpsZW5ndGgobGV2ZWxzKGRhZGVzWyxrXSkpKXtsaW5lcyhyb3dwZXJjWyxjXSxjb2w9cGFsZXRhW2NdKSB9CiAgICAgIGxlZ2VuZCgidG9wcmlnaHQiLCBsZXZlbHMoZGFkZXNbLGtdKSwgY29sPXBhbGV0YSwgbHR5PTIsIGNleD0wLjYpCiAgICAgIAogICAgICAjYW1iIHZhcmlhYmxlIGVuIGVpeCBkJ2FiY2lzc2VzCiAgICAgIG1hcmcgPC10YWJsZShkYWRlc1ssa10pL24KICAgICAgcHJpbnQoYXBwZW5kKCJDYXRlZ29yaWVzPSIsbGV2ZWxzKGRhZGVzWyxrXSkpKQogICAgICAKICAgICAgI3dpdGggbGVnZW5kCiAgICAgIHBsb3QobWFyZyx0eXBlPSJsIix5bGltPWMoMCwxKSxtYWluPXBhc3RlKCJQcm9wLiBvZiBwb3MgJiBuZWcgYnkiLG5hbWVzKGRhZGVzKVtrXSksIGxhcz0zKQogICAgICBmb3IoYyBpbiAxOmxlbmd0aChsZXZlbHMoYXMuZmFjdG9yKFApKSkpe2xpbmVzKHJvd3BlcmNbYyxdLGNvbD1wYWxldGFbY10pfQogICAgICBsZWdlbmQoInRvcHJpZ2h0IiwgbGV2ZWxzKGFzLmZhY3RvcihQKSksIGNvbD1wYWxldGEsIGx0eT0yLCBjZXg9MC42KQogICAgICAKICAgICAgI2NvbmRpY2lvbmFkZXMgYSBjb2x1bW5hIAogICAgICAjd2l0aCBsZWdlbmQKICAgICAgcGxvdChtYXJnLHR5cGU9Im4iLHlsaW09YygwLDEpLG1haW49cGFzdGUoIlByb3AuIG9mIHBvcyAmIG5lZyBieSIsbmFtZXMoZGFkZXMpW2tdKSwgbGFzPTMpCiAgICAgIGZvcihjIGluIDE6bGVuZ3RoKGxldmVscyhhcy5mYWN0b3IoUCkpKSl7bGluZXMoY29scGVyY1tjLF0sY29sPXBhbGV0YVtjXSl9CiAgICAgIGxlZ2VuZCgidG9wcmlnaHQiLCBsZXZlbHMoYXMuZmFjdG9yKFApKSwgY29sPXBhbGV0YSwgbHR5PTIsIGNleD0wLjYpCiAgICAgIAogICAgICB0YWJsZTwtdGFibGUoZGFkZXNbLGtdLFApCiAgICAgIHByaW50KCJDcm9zcyBUYWJsZToiKQogICAgICBwcmludCh0YWJsZSkKICAgICAgcHJpbnQoIkRpc3RyaWJ1Y2lvbnMgY29uZGljaW9uYWRlcyBhIGNvbHVtbmVzOiIpCiAgICAgIHByaW50KGNvbHBlcmMpCiAgICAgIAogICAgICAjZGlhZ3JhbWVzIGRlIGJhcnJlcyBhcGlsYWRlcyAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgCiAgICAgIAogICAgICBwYWxldGE8LXJhaW5ib3cobGVuZ3RoKGxldmVscyhkYWRlc1ssa10pKSkKICAgICAgCiAgICAgIGJhcnBsb3QodGFibGUoZGFkZXNbLGtdLCBhcy5mYWN0b3IoUCkpLCBiZXNpZGU9RkFMU0UsY29sPXBhbGV0YSApCiAgICAgIGxlZ2VuZCgidG9wcmlnaHQiLGxldmVscyhhcy5mYWN0b3IoZGFkZXNbLGtdKSkscGNoPTEsY2V4PTAuNSwgY29sPXBhbGV0YSkKICAgICAgCiAgICAgICNkaWFncmFtZXMgZGUgYmFycmVzIGFkb3NhZGVzCiAgICAgIAogICAgICBiYXJwbG90KHRhYmxlKGRhZGVzWyxrXSwgYXMuZmFjdG9yKFApKSwgYmVzaWRlPVRSVUUsY29sPXBhbGV0YSkKICAgICAgbGVnZW5kKCJ0b3ByaWdodCIsbGV2ZWxzKGFzLmZhY3RvcihkYWRlc1ssa10pKSxwY2g9MSxjZXg9MC41LCBjb2w9cGFsZXRhKQogICAgICAKICAgICAgcHJpbnQoIlRlc3QgQ2hpIHF1YWRyYXQ6ICIpCiAgICAgIHByaW50KGNoaXNxLnRlc3QoZGFkZXNbLGtdLCBhcy5mYWN0b3IoUCkpKQogICAgICAKICAgICAgcHJpbnQoInZhbG9yc1Rlc3Q6IikKICAgICAgcHJpbnQoIFZhbG9yVGVzdFhxdWFsaShQLGRhZGVzWyxrXSkpCiAgICAgICNjYWxjdWxhciBlbHMgcHZhbHVlcyBkZSBsZXMgcXVhbGkKICAgIH0KICB9Cn0jZW5kZm9yCgojZGVzY3JpcHRvcnMgZGUgbGVzIGNsYXNzZXMgbcOpcyBzaWduaWZpY2F0aXVzLiBBZmVnaXIgaW5mbyBxdWFsaXRzCmZvciAoYyBpbiAxOmxlbmd0aChsZXZlbHMoYXMuZmFjdG9yKFApKSkpIHsKICBpZighaXMubmEobGV2ZWxzKGFzLmZhY3RvcihQKSlbY10pKXsKICAgIHByaW50KHBhc3RlKCJQLnZhbHVlcyBwZXIgY2xhc3M6IixsZXZlbHMoYXMuZmFjdG9yKFApKVtjXSkpOwogICAgcHJpbnQoc29ydChwdmFsa1tjLF0pLCBkaWdpdHM9MykgCiAgfQp9CgojYWZlZ2lyIGxhIGluZm9ybWFjaW8gZGUgbGVzIG1vZGFsaXRhdHMgZGUgbGVzIHF1YWxpdGF0aXZlcyBhIGxhIGxsaXN0YSBkZSBwdmFsdWVzIGkgZmVyIG9yZGVuYWNpbyBnbG9iYWwKCiNzYXZpbmcgdGhlIGRhdGFmcmFtZSBpbiBhbiBleHRlcm5hbCBmaWxlCiN3cml0ZS50YWJsZShkZCwgZmlsZSA9ICJjcmVkc2NvQ2xlYW4uY3N2Iiwgc2VwID0gIjsiLCBuYSA9ICJOQSIsIGRlYyA9ICIuIiwgcm93Lm5hbWVzID0gRkFMU0UsIGNvbC5uYW1lcyA9IFRSVUUpCgoKYGBgCkZpbmRpbmdzOgoKRnJvbSB0aGUgYm94cGxvdCBvZiB2YWxlbmNlIHZzIG1vZGUsIHdlIGNhbiBzZWUgdGhhdCBtaW5vciBzb25ncyB0ZW5kIHRvIGhhdmUgbG93ZXIgdmFsZW5jZSAoc2FkZGVyIG1vb2QpIHRoYW4gbWFqb3Igc29uZ3MuClNpbWlsYXJseSwgc29uZ3MgaW4gdGhlIG1pbm9yIGtleSB0ZW5kIHRvIGhhdmUgbG93ZXIgdGVtcG8gY29tcGFyZWQgdG8gc29uZ3MgaW4gdGhlIG1ham9yIGtleSwgYWx0aG91Z2ggdGhlcmUgYXJlIG91dGxpZXJzLgoKSW50ZXJlc3RpbmdseSwgbWFueSBzb25ncyBpbiB0aGUgbWFqb3Iga2V5IGFyZSBpbiB0aGUga2V5IG9mIEcsIEMsIEQgYW5kIEEuCldoZXJlYXMgdGhlIG1vc3QgcG9wdWxhciBrZXkgZm9yIG1pbm9yIHNvbmdzIGFyZSBBLCBCIGFuZCBFLgoKRm9yIHBvcHVsYXJpdHksIHNvbmdzIGluIHRoZSBtaW5vciBrZXkgaGF2ZSBhIHdpZGVyIHJhbmdlIGNvbXBhcmVkIHRvIG1ham9yIHNvbmdzLgoKCkdlbnJlIHZzIHZhbGVuY2UuCgpgYGB7cn0KbGlicmFyeShkcGx5cikKbGlicmFyeShmb3JjYXRzKQpwbG90ZGF0YSA8LSBkZCAlPiUKICBncm91cF9ieSh0cmFja19nZW5yZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fdmFsZW5jZSA9IG1lYW4odmFsZW5jZSkpCiMgcGxvdCBtZWFuIHNhbGFyaWVzCmdncGxvdChwbG90ZGF0YSwgCiAgICAgICBhZXMoeCA9IGZjdF9yZW9yZGVyKHRyYWNrX2dlbnJlLCBtZWFuX3ZhbGVuY2UpLCAKICAgICAgICAgICB5ID0gbWVhbl92YWxlbmNlKSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpICsKICB4bGFiKCJHZW5yZSIpICsgeWxhYigiTWVhbiBWYWxlbmNlIikKYGBgCk9uZSBnZW5yZSBzdG9vZCBvdXQgd2hlbiBsb29raW5nIGF0IGhpZ2hlc3QgdmFsZW5jZTogciZiLiBUaGUgU2xlZXAgZ2VucmUgaGFzIHRoZSBsb3dlc3QgbWVhbiB2YWxlbmNlLgoKTmV4dCB3ZSBjYW4gZXhhbWluZSB0aGUgcmVsYXRpb25zaGlwIGJldHdlZW4gZ2VucmUgYW5kIGVuZXJneSwgYnkgY2FsY3VsYXRpbmcgdGhlIG1lYW4uCgpgYGB7cn0KcGxvdGRhdGEyIDwtIGRkICU+JQogIGdyb3VwX2J5KHRyYWNrX2dlbnJlKSAlPiUKICBzdW1tYXJpemUobWVhbl9lbmVyZ3kgPSBtZWFuKGVuZXJneSkpCiMgcGxvdCBtZWFuIHNhbGFyaWVzCmdncGxvdChwbG90ZGF0YTIsIAogICAgICAgYWVzKHggPSBmY3RfcmVvcmRlcih0cmFja19nZW5yZSwgbWVhbl9lbmVyZ3kpLCAKICAgICAgICAgICB5ID0gbWVhbl9lbmVyZ3kpKSArCiAgZ2VvbV9iYXIoc3RhdCA9ICJpZGVudGl0eSIpICsKICBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkKYGBgCkNsYXNzaWNhbCBzb25ncyBoYXZlIHRoZSBsZWFzdCBtZWFuIGVuZXJneSwgYW5kIGRydW0tYW5kLWJhc3Mgc29uZ3MgaGF2ZSB0aGUgaGlnaGVzdCBtZWFuIGVuZXJneS4KCldlIGNhbiBhbHNvIGV4YW1pbmUgdGhlIHJlbGF0aW9uc2hpcCBiZXR3ZWVuIGdlbnJlIGFuZCBkYW5jZWFiaWxpdHkKCmBgYHtyfQpwbG90ZGF0YTMgPC0gZGQgJT4lCiAgZ3JvdXBfYnkodHJhY2tfZ2VucmUpICU+JQogIHN1bW1hcml6ZShtZWFuX2RhbmNlYWJpbGl0eSA9IG1lYW4oZGFuY2VhYmlsaXR5KSkKIyBwbG90IG1lYW4gc2FsYXJpZXMKZ2dwbG90KHBsb3RkYXRhMywgCiAgICAgICBhZXMoeCA9IGZjdF9yZW9yZGVyKHRyYWNrX2dlbnJlLCBtZWFuX2RhbmNlYWJpbGl0eSksIAogICAgICAgICAgIHkgPSBtZWFuX2RhbmNlYWJpbGl0eSkpICsKICBnZW9tX2JhcihzdGF0ID0gImlkZW50aXR5IikgKwogIHNjYWxlX3hfZGlzY3JldGUoZ3VpZGUgPSBndWlkZV9heGlzKGFuZ2xlID0gOTApKQpgYGAKCgoKYGBge3J9CnBsb3RkYXRhMiA8LSBkZCAlPiUKICBncm91cF9ieSh0cmFja19nZW5yZSkgJT4lCiAgc3VtbWFyaXplKG1lYW5fZW5lcmd5ID0gbWVhbihlbmVyZ3kpKQojIHBsb3QgbWVhbiBzYWxhcmllcwpnZ3Bsb3QocGxvdGRhdGEyLCAKICAgICAgIGFlcyh4ID0gZmN0X3Jlb3JkZXIodHJhY2tfZ2VucmUsIG1lYW5fZW5lcmd5KSwgCiAgICAgICAgICAgeSA9IG1lYW5fZW5lcmd5KSkgKwogIGdlb21fYmFyKHN0YXQgPSAiaWRlbnRpdHkiKSArCiAgc2NhbGVfeF9kaXNjcmV0ZShndWlkZSA9IGd1aWRlX2F4aXMoYW5nbGUgPSA5MCkpCmBgYAoKCmBgYHtyfQpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSBtb2RlLCAKICAgICAgICAgICB5ID0gdmFsZW5jZSkpICsKICBnZW9tX2JveHBsb3QoKSArCiAgbGFicyh0aXRsZSA9ICJWYWxlbmNlIGRpc3RyaWJ1dGlvbiBieSBtb2RlIikKYGBgCgpFbmVyZ3kgdnMgbW9kZQoKYGBge3J9CmdncGxvdChkZCwgCiAgICAgICBhZXMoeCA9IG1vZGUsIAogICAgICAgICAgIHkgPSBlbmVyZ3kpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAiRW5lcmd5IGRpc3RyaWJ1dGlvbiBieSBtb2RlIikKYGBgCgpNaW5vciBzb25ncyBhY3R1YWxseSBoYXZlIGEgaGlnaGVyIHJhbmdlIG9mIGVuZXJneSBjb21wYXJlZCB0byBtYWpvciBzb25ncywgd2hpY2ggaXMgaW50ZXJlc3RpbmcgYmVjYXVzZSBvbmUgd291bGQgdGhpbmsgdGhhdCB0aGVyZSB3b3VsZCBiZSBtb3JlIGhhcHB5IHNvbmdzICh0eXBpY2FsbHkgbWFqb3Iga2V5KSB3aXRoIGhpZ2hlciBlbmVyZ3kuIEJ1dCB0aGlzIGNvdWxkIGJlIGJlY2F1c2UgbWFueSBvZiB0aGUgbGF0aW4gc29uZ3MgYXJlIGluIG1pbm9yIGtleS4KCmBgYHtyfQpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSBtb2RlLCAKICAgICAgICAgICB5ID0gYWNvdXN0aWNuZXNzKSkgKwogIGdlb21fYm94cGxvdCgpICsKICBsYWJzKHRpdGxlID0gIkFjb3VzdGljbmVzcyBkaXN0cmlidXRpb24gYnkgbW9kZSIpCmBgYAoKTG9va2luZyBhdCB2YWxlbmNlIHZzIGV4cGxpY2l0bmVzcywgd2Ugc2VlIHRoYXQgc29uZ3MgdGhhdCBhcmUgZXhwbGljaXQgdGVuZCB0byBoYXZlIGxvd2VyIHZhbGVuY2UgdGhhbiBzb25ncyB0aGF0IGFyZSBjbGVhbi4KCmBgYHtyfQpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSBleHBsaWNpdCwgCiAgICAgICAgICAgeSA9IHZhbGVuY2UpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAiVmFsZW5jZSBkaXN0cmlidXRpb24gYnkgZXhwbGljaXQiKSArCiAgICBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkKCmBgYAoKTG9va2luZyBhdCB2YWxlbmNlIHZzIGV4cGxpY2l0bmVzcywgd2Ugc2VlIHRoYXQgc29uZ3MgdGhhdCBhcmUgZXhwbGljaXQgdGVuZCB0byBoYXZlIGxvd2VyIHZhbGVuY2UgdGhhbiBzb25ncyB0aGF0IGFyZSBjbGVhbi4KCmBgYHtyfQpnZ3Bsb3QoZGQsIAogICAgICAgYWVzKHggPSBleHBsaWNpdCwgCiAgICAgICAgICAgeSA9IHZhbGVuY2UpKSArCiAgZ2VvbV9ib3hwbG90KCkgKwogIGxhYnModGl0bGUgPSAiVmFsZW5jZSBkaXN0cmlidXRpb24gYnkgZXhwbGljaXQiKSArCiAgICBzY2FsZV94X2Rpc2NyZXRlKGd1aWRlID0gZ3VpZGVfYXhpcyhhbmdsZSA9IDkwKSkKCmBgYAoKCiMjIE51bWVyaWNhbCB2cyBOdW1lcmljYWwKCgpgYGB7cn0KbnVtZXJpY2FsX29ubHkgPC0gZGQgJT4lIHNlbGVjdCgxOjIsIDQ6NSwgNywgOToxNCkKcGFpcnMobnVtZXJpY2FsX29ubHkpCgpwYW5lbC5jb3IgPC0gZnVuY3Rpb24oeCwgeSwgZGlnaXRzID0gMiwgcHJlZml4ID0gIiIsIGNleC5jb3IsIC4uLikKewogICAgdXNyIDwtIHBhcigidXNyIik7IG9uLmV4aXQocGFyKHVzcikpCiAgICBwYXIodXNyID0gYygwLCAxLCAwLCAxKSkKICAgIHIgPC0gYWJzKGNvcih4LCB5KSkKICAgIHR4dCA8LSBmb3JtYXQoYyhyLCAwLjEyMzQ1Njc4OSksIGRpZ2l0cyA9IGRpZ2l0cylbMV0KICAgIHR4dCA8LSBwYXN0ZTAocHJlZml4LCB0eHQpCiAgICBpZihtaXNzaW5nKGNleC5jb3IpKSBjZXguY29yIDwtIDAuOC9zdHJ3aWR0aCh0eHQpCiAgICB0ZXh0KDAuNSwgMC41LCB0eHQsIGNleCA9IGNleC5jb3IgKiByKQp9CnBhaXJzKG51bWVyaWNhbF9vbmx5LCBsb3dlci5wYW5lbCA9IHBhbmVsLnNtb290aCwgdXBwZXIucGFuZWwgPSBwYW5lbC5jb3IsCiAgICAgIGdhcD0wLCByb3cxYXR0b3A9RkFMU0UpCgpgYGAKCg==